#!/usr/bin/env python
import argparse
import logging
import random
import sys
import os
from ConfigParser import ConfigParser
from ConfigParser import ParsingError
#Local imports
import executionhelper
import experimenthelper
from filehelper import move_results
from filehelper import create_archive
from loghelper import init_logging
from loghelper import add_logfile
from config import ConfigValues


def shutdown(reason=0):
	"""
	Shutdown function to turn off logging and then exit
	"""
	log = logging.getLogger('core')
	if reason == -1:
		log.error('Shuting down after error')
	elif reason == 0:
		log.info('Shuting down')
	else:
		log.warning('Shuting down for reason {}'.format(reason))
	logging.shutdown()
	sys.exit(reason)

def get_arguements():
	"""
	Parse commandline arguements using ArgParse
	If no arguments are present we assume the user want a time estimate
	"""
	parser = argparse.ArgumentParser(description='MobiEmu start script')
	group = parser.add_mutually_exclusive_group()
	group.add_argument("-r", "--run", action="store_true", help="Run the experiment")
	group.add_argument("-c", "--cleanup", action="store_true", help="Remove and stop all lxc-nodes, bridges and tap devices")
	group.add_argument("-m", "--moveresults", action="store_true", help="Move results")
	group.add_argument("-a", "--archive", action="store_true", help="Archive configuration files and store them")
	parser.add_argument('--conf', default='settings.cfg', type=str, help="Specify the settings file to use during a run, default is 'settings.cfg'. To have this file stored on backup the variable 'include_config' needs to be True.")
	parser.add_argument('--log', choices=['INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL'], help="Select which level to log at. Information comming from the experiment will be logged at level INFO by default", default='INFO')
	return parser.parse_args()

def get_configuration(log_name, settings_file):
	"""
	Parse the settings file and return a dictionary with the values
	"""
	config = {}
	cfg = ConfigParser()
	log = logging.getLogger(log_name)
	try:
		if settings_file == 'settings.cfg':
			res = cfg.read(os.path.abspath(settings_file))
		else:
			if os.path.isfile(settings_file):
				res = cfg.read(settings_file)
			else:
				log.critical('Provided settings file is not a proper file, check that the path is correct and try again.')
				raise ParsingError('Could not read settings file, {}'.format(settings_file))
		if not res:
			raise ParsingError('Could not find configuration file "{}"'.format(settings_file))
	except ParsingError, err:
		log.exception("Could not read setting file")
		shutdown(-1)
	log.debug('Parsing section "general" of the configuration')
	config[ConfigValues.TOTAL_NODES] = cfg.getint('general','total_nodes')
	config[ConfigValues.DURATION] = cfg.getint('general','experiment_duration')
	config[ConfigValues.INITIAL_WAIT] = cfg.getint('general','initial_wait')
	config[ConfigValues.SHUTDOWN_WAIT] = cfg.getint('general','shutdown_wait')
	#config[ConfigValues.SHOW_DEBUG] = cfg.getboolean('general','show_debug_messages')
	#config[ConfigValues.USE_CHROOT] = cfg.getboolean('general','use_chroot')
	config[ConfigValues.CFG] = cfg
	#Add settings file to configuration, this is retreived later when archiving
	cfg.set('source_archiver', 'config_file', settings_file)
	env = [{} for i in range((config[ConfigValues.TOTAL_NODES] + 1))]
	if cfg.has_section(cfg.get('virtual_machine', 'file')):
		log.info('Adding virtual machine configuration to environment')
		for name, value in cfg.items(cfg.get('virtual_machine', 'file')):
			env[0][name] = value
	log.debug('Adding configuration section "general" to environment')
	for item, value in cfg.items('general'):
		env[0][item] = value
	log.debug('Adding environment')
	for key in os.environ.keys():
		env[0][key] = os.environ[key]
	#Set seed for the Python random generator
	log.debug('Initialising random generator')
	random.seed(int(cfg.get('general','initial_random_seed')))
	return config, env

def main(args):
	"""
	Main method, this method retreives the configuration from the settings file
	it then does what the user has specified on the commandline.
	"""
	log = logging.getLogger('core')
	log.info('Starting main')
	log.debug('Parsing configuration file')
	config, env = get_configuration('core.config', args.conf)
	log.debug("Config: {}, Environment: {}".format(config, env))
	
	log.debug('Done parsing config, starting main task: {}'.format(args))
	try:
		if args.run:
			log.info('Running experiment')
			experimenthelper.run_experiment(config[ConfigValues.CFG], False, env, config[ConfigValues.INITIAL_WAIT], config[ConfigValues.DURATION], config[ConfigValues.SHUTDOWN_WAIT], config[ConfigValues.TOTAL_NODES])
			log.info('Finnished experiment')
		elif args.cleanup:
			log.info('Cleaning up')
			executionhelper.safe_exec([config[ConfigValues.CFG].get('directories', 'modules') + '/' + config[ConfigValues.CFG].get('virtual_machine', 'file'), 'remove_devices'], logging.getLogger('core.cleanup'), config[ConfigValues.CFG], env)
			log.info('Cleanup complete')
		elif args.moveresults:
			#log.info('Moving results from dumps to results')
			#move_results(logging.getLogger('core.move'), config[ConfigValues.CFG], env[0])
			#log.info('Done moving files')
			log.warn('Method no longer in use, will be removed soon')
		elif args.archive:
			#log.info('Archiving results')
			#create_archive(logging.getLogger('core.archiver'), config[ConfigValues.CFG], env[0])
			#log.info('Archive made')
			log.warn('Method no longer in use, will be removed soon')
		else:
			total_exp = experimenthelper.calculate_run(config[ConfigValues.CFG])
			#Estimate the time the whole experiment would take
			estimated_total_time = total_exp * (config[ConfigValues.DURATION] + config[ConfigValues.INITIAL_WAIT] + config[ConfigValues.SHUTDOWN_WAIT])
			print "Total number of experiments:", total_exp
			print "This would approximately take", estimated_total_time,  "seconds, or", estimated_total_time/3600.0, "hours"
	except:
		add_logfile(log, 'error.log')
		log.exception('A problem occured during run')
		shutdown(-1)
	shutdown(0)
		
if __name__ == '__main__':
	#Get commandline arguments
	args = get_arguements()
	#Initialise the logging framework
	init_logging(getattr(logging, args.log))
	main(args)